// 迷宫单元格类型
export type Cell = {
  x: number;
  y: number;
  walls: {
    top: boolean;
    right: boolean;
    bottom: boolean;
    left: boolean;
  };
  visited: boolean;
};

// 迷宫类型
export type Maze = {
  width: number;
  height: number;
  cells: Cell[][];
  start: { x: number; y: number };
  end: { x: number; y: number };
};

// 玩家位置类型
export type PlayerPosition = {
  x: number;
  y: number;
};

// 方向枚举
export enum Direction {
  UP,
  RIGHT,
  DOWN,
  LEFT,
}

// 获取相邻单元格
const getNeighbor = (
  maze: Maze,
  cell: Cell,
  direction: Direction
): Cell | null => {
  const { x, y } = cell;
  let nx = x;
  let ny = y;

  switch (direction) {
    case Direction.UP:
      ny = y - 1;
      break;
    case Direction.RIGHT:
      nx = x + 1;
      break;
    case Direction.DOWN:
      ny = y + 1;
      break;
    case Direction.LEFT:
      nx = x - 1;
      break;
  }

  // 检查边界
  if (nx < 0 || nx >= maze.width || ny < 0 || ny >= maze.height) {
    return null;
  }

  return maze.cells[ny][nx];
};

// 移除两个单元格之间的墙
const removeWall = (current: Cell, next: Cell) => {
  const dx = next.x - current.x;
  const dy = next.y - current.y;

  if (dx === 1) {
    // next在右边
    current.walls.right = false;
    next.walls.left = false;
  } else if (dx === -1) {
    // next在左边
    current.walls.left = false;
    next.walls.right = false;
  } else if (dy === 1) {
    // next在下边
    current.walls.bottom = false;
    next.walls.top = false;
  } else if (dy === -1) {
    // next在上边
    current.walls.top = false;
    next.walls.bottom = false;
  }
};

// 使用深度优先搜索生成迷宫
export const generateMaze = (width: number, height: number): Maze => {
  // 初始化迷宫
  const cells: Cell[][] = [];
  for (let y = 0; y < height; y++) {
    const row: Cell[] = [];
    for (let x = 0; x < width; x++) {
      row.push({
        x,
        y,
        walls: {
          top: true,
          right: true,
          bottom: true,
          left: true,
        },
        visited: false,
      });
    }
    cells.push(row);
  }

  const maze: Maze = {
    width,
    height,
    cells,
    start: { x: 0, y: 0 },
    end: { x: width - 1, y: height - 1 },
  };

  // 深度优先搜索生成迷宫
  const stack: Cell[] = [];
  const startCell = cells[0][0];
  startCell.visited = true;
  stack.push(startCell);

  while (stack.length > 0) {
    const current = stack[stack.length - 1];
    const neighbors: Cell[] = [];

    // 获取所有未访问的相邻单元格
    [Direction.UP, Direction.RIGHT, Direction.DOWN, Direction.LEFT].forEach(
      (direction) => {
        const neighbor = getNeighbor(maze, current, direction);
        if (neighbor && !neighbor.visited) {
          neighbors.push(neighbor);
        }
      }
    );

    if (neighbors.length === 0) {
      // 没有未访问的相邻单元格，回溯
      stack.pop();
    } else {
      // 随机选择一个未访问的相邻单元格
      const next = neighbors[Math.floor(Math.random() * neighbors.length)];
      next.visited = true;
      removeWall(current, next);
      stack.push(next);
    }
  }

  // 重置visited标志
  for (let y = 0; y < height; y++) {
    for (let x = 0; x < width; x++) {
      cells[y][x].visited = false;
    }
  }

  return maze;
};

// 检查移动是否有效
export const isValidMove = (
  maze: Maze,
  position: PlayerPosition,
  direction: Direction
): boolean => {
  const { x, y } = position;
  const cell = maze.cells[y][x];

  switch (direction) {
    case Direction.UP:
      return !cell.walls.top;
    case Direction.RIGHT:
      return !cell.walls.right;
    case Direction.DOWN:
      return !cell.walls.bottom;
    case Direction.LEFT:
      return !cell.walls.left;
  }
};

// 移动玩家
export const movePlayer = (
  position: PlayerPosition,
  direction: Direction
): PlayerPosition => {
  const { x, y } = position;
  let nx = x;
  let ny = y;

  switch (direction) {
    case Direction.UP:
      ny = y - 1;
      break;
    case Direction.RIGHT:
      nx = x + 1;
      break;
    case Direction.DOWN:
      ny = y + 1;
      break;
    case Direction.LEFT:
      nx = x - 1;
      break;
  }

  return { x: nx, y: ny };
};

// 检查是否到达终点
export const isAtEnd = (
  position: PlayerPosition,
  end: { x: number; y: number }
): boolean => {
  return position.x === end.x && position.y === end.y;
};